package larpplanner.gui;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import larpplanner.database.FicCharacter;
import larpplanner.database.Player;
import larpplanner.database.Quest;

import com.cloudgarden.resource.SWTResourceManager;

import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.SWT;

public class QuestEditDialog extends org.eclipse.swt.widgets.Dialog {

	private GUISafeLARPManager mngr = GUISafeLARPManager.get();
	
	private Quest quest;
	private Map<String,Long> playerIdByName = new HashMap<String, Long>();;
	private boolean newQuestFlag = false;
	private boolean normalExit = false;
	private int questSize;
	
    private Shell dialogShell;
    private Button dateBtn;
    private Text nameTxt;
    private Table playersTbl;
    private Button rmvPlayer;
    private Button addPlayer;
    private Composite plyrBtnHoldr;
    private Label label1;
    private Composite btnHolder;
    private Button okBtn;
    private Label detailsLbl;
    private Label NameLbl;
    private Label locationLbl;
    private Label playersLbl;
    private TableColumn charCol;
    private TableColumn playerCol;
    private Text detailsTxt;
    private Text locationTxt;

    private void initLogic() {
        
        if (quest == null) {
            okBtn.setText("Create");
            quest = new Quest();
            quest.setName("new quest");
            newQuestFlag = true;
            mngr.add(Quest.class, quest, new SafeCallback<Long>() {
				public void onReturn(Long result) {
					if(result == -1)
            			PopMessage.errorMessage("quest add failed");
					else
						quest.setId(result);
				}
			});
            questSize = 0;
        }
        else {
        	okBtn.setText("Update");
            nameTxt.setText(quest.getName());
            if(quest.getLocation() != null)
            		locationTxt.setText(quest.getLocation());
            if(quest.getDetails() != null)
            	detailsTxt.setText(quest.getDetails());
            if(quest.getDate() != null)
            	dateBtn.setText(dateFormatter(quest.getDate()));
            
            Map<Player, FicCharacter> players = quest.getParticipants();
            if(players == null){
            	PopMessage.errorMessage("quest has null players");
            }
            else{
            	questSize = players.size();
            	for(Map.Entry<Player, FicCharacter> entry : players.entrySet()) {
            		TableItem item = new TableItem(playersTbl, SWT.NONE);
            		item.setText(0, entry.getKey().getName());
            		item.setText(1, entry.getValue().getName());
            		playerIdByName.put(entry.getKey().getName(), entry.getKey().getId());
            	}
            }
        }

        dateBtn.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                // open a date window
            	Display display = dialogShell.getDisplay();
                DateWin date = new DateWin(new Shell(display), SWT.DATE);
                Timestamp nts;
                if(quest != null && quest.getDate() != null) {
                	Timestamp ts = quest.getDate();
                	Calendar c = Calendar.getInstance();
                	c.setTime(ts);
                	nts = date.open(c.get(Calendar.YEAR),
                					c.get(Calendar.MONTH),
                					c.get(Calendar.DAY_OF_MONTH),
                					c.get(Calendar.HOUR_OF_DAY),
                					c.get(Calendar.MINUTE));
                }else{
                	nts = date.open();
                }
                dateBtn.setText(dateFormatter(nts));
                quest.setDate(nts);
            }
        });
        
        okBtn.addSelectionListener(new SelectionAdapter() {
        	public void widgetSelected(SelectionEvent e) {
        		if(!checkValid())
        			return;
        		
        		mngr.update(Quest.class, quest, new SafeCallback<Boolean>() {
        			public void onReturn(Boolean result) {
        				if(!result)
        					PopMessage.errorMessage("quest edit dialog: quest update failed");
        				dialogShell.dispose();
        			}
        		});
        		
        		normalExit = true;
        	}
        });
        
        rmvPlayer.setEnabled(false);
        
        // remove a player
        rmvPlayer.addSelectionListener(new SelectionAdapter() {
        	public void widgetSelected(SelectionEvent e) {
        		int idx = playersTbl.getSelectionIndex();
        		String playerName = playersTbl.getItem(idx).getText(0);
        		Long playerIdToRemove = playerIdByName.get(playerName);
        		mngr.removeParticipant(quest.getId(), playerIdToRemove, new SafeCallback<Boolean>() {
        			public void onReturn(Boolean result) {
        				if(!result)
							PopMessage.errorMessage("quest update failed");
        				else
        					questSize--;
        			}
        		});
        		playerIdByName.remove(playerName);
        		playersTbl.remove(idx);
        		rmvPlayer.setEnabled(false);
        	}
        });
        
        // add a new player - player is added to the DB by the character window
        addPlayer.addSelectionListener(new SelectionAdapter() {
        	public void widgetSelected(SelectionEvent e) {
        		Display display = dialogShell.getDisplay();
        		CharWin charWin = new CharWin(new Shell(display), SWT.NONE, quest, null);
        		// note: charWin will add the new player to the quest object
        		Long newPlayerId = charWin.open();
        		if(newPlayerId != -1L) {
        			questSize++;
        			String playerName = charWin.getPlayerName();
        			String playerCharName = charWin.getCharName();
                	TableItem item = new TableItem (playersTbl, SWT.NONE);
                	item.setText(0, playerName);
                	item.setText(1, playerCharName);
                	playerIdByName.put(playerName, newPlayerId);
                }
        	}
		});
        
        playersTbl.addSelectionListener(new SelectionListener() {
			// on single click - make the remove button active
        	public void widgetSelected(SelectionEvent e) {
				rmvPlayer.setEnabled(true);
			}
			
			// on double click - edit the player and character
			public void widgetDefaultSelected(SelectionEvent e) {
				Display display = dialogShell.getDisplay();
				TableItem item = playersTbl.getItem(playersTbl.getSelectionIndex());
				CharWin charWin = new CharWin(new Shell(display), SWT.NONE, quest, item.getText(0));
				String prevPlayerName = item.getText(0);
				String playerName = item.getText(0);
				String playerCharName = "";
				// TODO: make sure current player name and current character are selected
				Long newPlayerId = charWin.open();
        		if(newPlayerId != -1){
        			item.setText(0, playerName);
        			item.setText(1, playerCharName);
        			playerIdByName.remove(prevPlayerName);
        			playerIdByName.put(playerName, newPlayerId);
        		}
			}
		});
        
        nameTxt.addFocusListener(new FocusAdapter() {
        	public void focusLost(FocusEvent e) {
        		quest.setName(nameTxt.getText());
        	}
        });
        
        detailsTxt.addFocusListener(new FocusAdapter() {
        	public void focusLost(FocusEvent e) {
        		quest.setDetails(detailsTxt.getText());
        	}
        });
        
        locationTxt.addFocusListener(new FocusAdapter() {
        	public void focusLost(FocusEvent e) {
        		quest.setLocation(locationTxt.getText());
        	}
        });
    }
    
    public static void main(String[] args) {
        try {
            Display display = Display.getDefault();
            Shell shell = new Shell(display);
            QuestEditDialog inst = new QuestEditDialog(shell, SWT.NULL, null);
            inst.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public QuestEditDialog(Shell parent, int style, Quest editQuest) {
        super(parent, style);
        quest = editQuest;
        initGUI();
        initLogic();
    }
    
    public String getQuestName() {
    	return quest.getName();
    }
    
    public int getQuestSize() {
    	return questSize;
    }
    
    public Quest open() {
        try {
            dialogShell.setLocation(getParent().toDisplay(100, 100));
            dialogShell.open();
            Display display = dialogShell.getDisplay();
            while (!dialogShell.isDisposed()) {
                if (!display.readAndDispatch())
                    display.sleep();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(!normalExit || !checkValid()) {
        	if(newQuestFlag) {
        		mngr.del(Quest.class, quest.getId(), new SafeCallback<Boolean>() {
					public void onReturn(Boolean result) {
						if(!result)
							PopMessage.errorMessage("failed to remove this unsaved quest");
					}
        		});
        	}
        	return null;
        }
        return quest;
    }
    
    /** convert a timestamp to this widget's date format */
    private String dateFormatter(Timestamp t) {
    	SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy 'at' HH:mm");
    	return df.format(t);
    }
    
    /** this function should be used to check whether the quest object is valid */
    private boolean checkValid() {
    	if(quest.getName() == null || quest.getName() == ""){
    		PopMessage.errorMessage("quest must have a name");
    		return false;
    	}
    	// TODO: add more validness checks
    	return true;
    }
    
    private void initGUI() {
    	try {
    		Shell parent = getParent();
            dialogShell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
            SWTResourceManager.registerResourceUser(dialogShell);
            GridLayout dialogShellLayout = new GridLayout();
            dialogShellLayout.numColumns = 3;
            dialogShellLayout.marginTop = 5;
            dialogShellLayout.marginRight = 5;
            dialogShellLayout.marginLeft = 5;
            dialogShellLayout.marginBottom = 5;
            dialogShell.setLayout(dialogShellLayout);
            dialogShell.layout();
            dialogShell.pack();            
            dialogShell.setSize(490, 500);
            dialogShell.setText("Quest Details");
            {
            	NameLbl = new Label(dialogShell, SWT.NONE);
            	GridData NameLblLData = new GridData();
            	NameLbl.setLayoutData(NameLblLData);
            	NameLbl.setText("Name:");
            }
            {
            	nameTxt = new Text(dialogShell, SWT.BORDER);
            	GridData nameTxtLData = new GridData();
            	nameTxtLData.widthHint = 16777224;
            	nameTxtLData.grabExcessHorizontalSpace = true;
            	nameTxt.setLayoutData(nameTxtLData);
            	nameTxt.setText("");
            }
            {
            	dateBtn = new Button(dialogShell, SWT.PUSH | SWT.CENTER);
            	GridData dateBtnLData = new GridData();
            	dateBtnLData.grabExcessHorizontalSpace = true;
            	dateBtnLData.widthHint = 16777224;
            	dateBtn.setLayoutData(dateBtnLData);
            	dateBtn.setText("DD/MM/YYYY at HH:MM");
            }
            {
            	locationLbl = new Label(dialogShell, SWT.NONE);
            	GridData locationLblLData = new GridData();
            	locationLbl.setLayoutData(locationLblLData);
            	locationLbl.setText("Location:");
            }
            {
            	locationTxt = new Text(dialogShell, SWT.BORDER);
            	GridData nameTxtLData = new GridData();
            	nameTxtLData.widthHint = 16777224;
            	nameTxtLData.grabExcessHorizontalSpace = true;
            	locationTxt.setLayoutData(nameTxtLData);
            	locationTxt.setText("");
            }
            {
            	label1 = new Label(dialogShell, SWT.NONE);
            	GridData label1LData = new GridData();
            	label1.setLayoutData(label1LData);
            }
            {
            	detailsLbl = new Label(dialogShell, SWT.NONE);
            	GridData detailsLblLData = new GridData();
            	detailsLblLData.verticalAlignment = GridData.BEGINNING;
            	detailsLbl.setLayoutData(detailsLblLData);
            	detailsLbl.setText("Details:");
            }
            {
                detailsTxt = new Text(dialogShell, SWT.MULTI | SWT.WRAP | SWT.BORDER);
                GridData detailsTxtLData = new GridData();
                detailsTxtLData.grabExcessHorizontalSpace = true;
                detailsTxtLData.horizontalSpan = 2;
                detailsTxtLData.widthHint = 443;
                detailsTxtLData.heightHint = 98;
                detailsTxt.setLayoutData(detailsTxtLData);
                detailsTxt.setText("");
            }
            {
                playersLbl = new Label(dialogShell, SWT.NONE);
                GridData playersLblLData = new GridData();
                playersLblLData.horizontalSpan = 2;
                playersLbl.setLayoutData(playersLblLData);
                playersLbl.setText("Participating Players:");
                playersLbl.setFont(SWTResourceManager.getFont("Lucida Grande", 14, 0, false, false));
            }
            {
                GridData playersTblLData = new GridData();
                playersTblLData.grabExcessHorizontalSpace = true;
                playersTblLData.grabExcessVerticalSpace = true;
                playersTblLData.widthHint = 433;
                playersTblLData.heightHint = 300;
                playersTblLData.horizontalSpan = 3;
                playersTbl = new Table(dialogShell, SWT.BORDER);
                playersTbl.setLayoutData(playersTblLData);
                playersTbl.setHeaderVisible(true);
                playersTbl.setLinesVisible(true);
                {
                    playerCol = new TableColumn(playersTbl, SWT.NONE);
                    playerCol.setText("Player");
                    playerCol.setWidth(227);
                }
                {
                    charCol = new TableColumn(playersTbl, SWT.NONE);
                    charCol.setText("Character");
                    charCol.setWidth(220);
                }
            }
            {
            	plyrBtnHoldr = new Composite(dialogShell, SWT.NONE);
            	RowLayout plyrBtnHoldrLayout = new RowLayout(org.eclipse.swt.SWT.HORIZONTAL);
            	plyrBtnHoldrLayout.spacing = 15;
            	GridData plyrBtnHoldrLData = new GridData();
            	plyrBtnHoldrLData.widthHint = 119;
            	plyrBtnHoldrLData.heightHint = 31;
            	plyrBtnHoldrLData.horizontalSpan = 3;
            	plyrBtnHoldr.setLayoutData(plyrBtnHoldrLData);
            	plyrBtnHoldr.setLayout(plyrBtnHoldrLayout);
            	{
            		addPlayer = new Button(plyrBtnHoldr, SWT.PUSH | SWT.CENTER);
            		RowData addPlayerLData = new RowData();
            		addPlayer.setLayoutData(addPlayerLData);
            		addPlayer.setText("Add");
            	}
            	{
            		rmvPlayer = new Button(plyrBtnHoldr, SWT.PUSH | SWT.CENTER);
            		RowData rmvPlayerLData = new RowData();
            		rmvPlayer.setLayoutData(rmvPlayerLData);
            		rmvPlayer.setText("Remove");
            	}
            }
            {
                GridData btnHolderLData = new GridData();
                btnHolderLData.horizontalAlignment = GridData.CENTER;
                btnHolderLData.grabExcessHorizontalSpace = true;
                btnHolderLData.horizontalSpan = 3;
                btnHolder = new Composite(dialogShell, SWT.NONE);
                RowLayout btnHolderLayout = new RowLayout(org.eclipse.swt.SWT.HORIZONTAL);
                btnHolderLayout.spacing = 15;
                btnHolder.setLayout(btnHolderLayout);
                btnHolder.setLayoutData(btnHolderLData);
                {
                	okBtn = new Button(btnHolder, SWT.PUSH | SWT.CENTER);
                	RowData okBtnLData = new RowData();
                	okBtn.setLayoutData(okBtnLData);
                	okBtn.setText("ok");
                }
            }
    	}catch (Exception e) {
            e.printStackTrace();
        }
    }
}
